package com.jxl.infra.basic.es.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.jxl.common.entity.PageResult;
import com.jxl.infra.basic.es.annotation.HighLight;
import com.jxl.infra.basic.es.annotation.QueryEs;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.text.Text;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.*;


@Component
public class EsUtil<V> {


    @Resource
    private RestHighLevelClient client;

    /**
     * 添加文档
     * @param indexName
     * @param v
     */
    public void add(String indexName,V v){
        IndexRequest indexRequest = new IndexRequest();
        indexRequest.index(indexName);
        String s = JSON.toJSONString(v);
        indexRequest.source(s, XContentType.JSON);
        try {
            client.index(indexRequest, RequestOptions.DEFAULT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 高亮分页查询
     * @param index
     * @param keyWord
     * @param pageNo
     * @param pageSize
     * @param v
     * @return
     */
    public PageResult<V> page(String index,String keyWord,long pageNo,long pageSize,Class<V> v){
        SearchRequest searchRequest = new SearchRequest(index);

        Field[] fields = v.getDeclaredFields();
        List<String> highList = new ArrayList<>(); //高亮字段
        List<String> query = new ArrayList<>(); //查询字段
        List<String> normal = new ArrayList<>(); //普通字段
        //分离加入条件的字段
        for (Field field : fields) {
            if (field.isAnnotationPresent(HighLight.class)){
                highList.add(field.getName());
            }
            if (field.isAnnotationPresent(QueryEs.class)){
                query.add(field.getName());
            }
            if (!field.isAnnotationPresent(HighLight.class) && !field.isAnnotationPresent(QueryEs.class)){
                normal.add(field.getName());
            }
        }

        //设置高亮
        HighlightBuilder highlightBuilder = new HighlightBuilder();
        if (highList!=null && highList.size()>0){
            highlightBuilder.preTags("<span style='color:red'>");
            highlightBuilder.postTags("</span>");
            for (String s : highList) {
                highlightBuilder.field(s);
            }
        }

        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.highlighter(highlightBuilder);
//        //分页
        sourceBuilder.from((int) ((pageNo-1L)*pageSize));
        sourceBuilder.size((int) pageSize);
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        if (query!=null && query.size()>0){
            for (String s : query) {
                boolQueryBuilder.should(QueryBuilders.matchQuery(s,keyWord));
            }
        }
        sourceBuilder.query(boolQueryBuilder);
        searchRequest.source(sourceBuilder);

        //发送
        try {
            SearchResponse search = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHit[] hits = search.getHits().getHits();
            int total = search.getTotalShards();//总数
            List<V> list = new ArrayList<>();
            for (SearchHit hit : hits) {
                //进行值的提取
                String sourceAsString = hit.getSourceAsString();//这个没有高亮的值
                //接下来进行替换
                Map<String, HighlightField> highlightFields = hit.getHighlightFields();
                String s = replaceHighlight(highList, sourceAsString, highlightFields);
                V v1 = JSON.parseObject(s, v);
                list.add(v1);
            }
            //设置分页
            PageResult<V> pageResult = new PageResult<V>();
            pageResult.setResult(list);
            pageResult.setPageNo(pageNo);
            pageResult.setPageSize(pageSize);
            pageResult.setTotal((long) total);
            return pageResult;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 高亮替换
     * @param highFiled
     * @param jsonString
     * @param hign
     * @return
     */
    private String replaceHighlight(List<String> highFiled,String jsonString,Map<String, HighlightField> hign){
        if (highFiled==null || highFiled.size()==0) return jsonString;

        for (String fieldName : highFiled) {
            HighlightField highlightField = hign.get(fieldName);
            if (highlightField==null) continue;
            String to = "";
            for (Text fragment : highlightField.getFragments()) {
                to+=fragment.toString();
            }
            JSONObject jsonObject = JSON.parseObject(jsonString);
            JSONObject jsonObject1 = jsonObject.fluentPut(fieldName, to);
            jsonString = JSON.toJSONString(jsonObject1);
        }
        return jsonString;
    }
}
